/**************************************************************************
 *
 * Copyright (c) 2002 - 2011 by Computer Architecture Department,
 * Universitat Politecnica de Catalunya.
 * All rights reserved.
 *
 * The contents of this file may not be disclosed to third parties,
 * copied or duplicated in any form, in whole or in part, without the
 * prior permission of the authors, Computer Architecture Department
 * and Universitat Politecnica de Catalunya.
 *
 */

////////////////////////////////////////////////////////////////////////////////

#include "Items/ClassDescription.hpp"
#include "Items/MethodDescription.hpp"
#include "Generator/ClassGenerator.hpp"

using namespace std;
using namespace dxcodegen::Items;
using namespace dxcodegen::Generator;

////////////////////////////////////////////////////////////////////////////////

ClassGenerator::ClassGenerator(ClassDescription& cdes, const string& outputPath) :
m_classDescription(cdes),
m_outputPath(outputPath),
m_classNameSuffix("Capture")
{
  string comment;
  GenerateHeaderComment(comment);
  SetHeaderComment(comment);  
}

////////////////////////////////////////////////////////////////////////////////

void ClassGenerator::GenerateCode()
{
  GenerateHpp();
  GenerateCpp();
}

////////////////////////////////////////////////////////////////////////////////

string ClassGenerator::GetClassName()
{
  return m_classDescription.GetName()+m_classNameSuffix;
}

////////////////////////////////////////////////////////////////////////////////

void ClassGenerator::GenerateHeaderComment(string& comment)
{
  comment += "////////////////////////////////////////////////////////////////////////////////" "\n";
  comment += "// class " + GetClassName() + "\n";
  comment += "//" "\n";
  comment += "// Autogenerated on " + GetDateTimeNow() + " by DXCodeGen\n";
  comment += "//" "\n";
  comment += "// Copyright (c) 2006 by David Abella" "\n";
  comment += "////////////////////////////////////////////////////////////////////////////////" "\n";
  comment += "\n";
}

////////////////////////////////////////////////////////////////////////////////

string ClassGenerator::GetDateTimeNow()
{
  string datetime;
  char buffer[256];
  struct _timeb ltime;
  struct tm* today;

  _ftime(&ltime);
  today = localtime(&(ltime.time));
  strftime(buffer, sizeof(buffer), "%d/%m/%Y %H:%M:%S", today);        
  datetime = buffer;

  return datetime;
}

////////////////////////////////////////////////////////////////////////////////

void ClassGenerator::GenerateHpp()
{
  string filename = GetClassName()+".hpp";
  ofstream* sortida = CreateFilename(m_outputPath+filename);
  if (sortida && sortida->is_open())
  {
    cout << "Creating '" << filename << "'" << endl;
    GenerateClassBody(sortida);
  }
  CloseFilename(sortida);
}

////////////////////////////////////////////////////////////////////////////////

void ClassGenerator::GenerateCpp()
{
  string filename = GetClassName()+".cpp";
  ofstream* sortida = CreateFilename(m_outputPath+filename);
  if (sortida && sortida->is_open())
  {
    cout << "Creating '" << filename << "'" << endl;
    GenerateClassMethods(sortida);
  }
  CloseFilename(sortida);
}

////////////////////////////////////////////////////////////////////////////////

void ClassGenerator::GenerateClassBody(ofstream* of)
{
  ofstream& sortida = *of;

  sortida << "#include \"stdafx.h\"" << endl;
  sortida << endl;  
  
  sortida << "class " << GetClassName() << " : public " << m_classDescription.GetName() << endl;
  sortida << "{" << endl;

  for (unsigned int i=0; i < m_classDescription.GetMethodsCount(); i++)
  {
    sortida << "  ";
    sortida << m_classDescription.GetMethod(i).GetType();
    sortida << " ";
    sortida << m_classDescription.GetMethod(i).GetName();
    sortida << "(";

    for (unsigned int j=0; j < m_classDescription.GetMethod(i).GetParamsCount(); j++)
    {
      sortida << m_classDescription.GetMethod(i).GetParam(j).type;
      if (!m_classDescription.GetMethod(i).GetParam(j).type.empty())
      {
        sortida << " ";
      }
      sortida << m_classDescription.GetMethod(i).GetParam(j).name;
      if (j+1 < m_classDescription.GetMethod(i).GetParamsCount())
      {
        sortida << ", ";
      }
    }

    sortida << ");" << endl;
  }

  sortida << "};" << endl;
}

////////////////////////////////////////////////////////////////////////////////

void ClassGenerator::GenerateClassMethods(std::ofstream* of)
{
  ofstream& sortida = *of;

  sortida << "#include \"" << GetClassName() << ".hpp\"" << endl;
  sortida << endl;
  
  for (unsigned int i=0; i < m_classDescription.GetMethodsCount(); i++)
  {
    GenerateClassMethod(of, i);
  }
}

////////////////////////////////////////////////////////////////////////////////

void ClassGenerator::GenerateClassMethod(std::ofstream* of, unsigned int position)
{
  ofstream& sortida = *of;

  sortida << m_classDescription.GetMethod(position).GetType();
  sortida << " ";
  sortida << GetClassName() << "::";
  sortida << m_classDescription.GetMethod(position).GetName();
  sortida << "(";

  for (unsigned int i=0; i < m_classDescription.GetMethod(position).GetParamsCount(); i++)
  {
    sortida << m_classDescription.GetMethod(position).GetParam(i).type;
    if (!m_classDescription.GetMethod(position).GetParam(i).type.empty())
    {
      sortida << " ";
    }
    sortida << m_classDescription.GetMethod(position).GetParam(i).name;
    if (i+1 < m_classDescription.GetMethod(position).GetParamsCount())
    {
      sortida << ", ";
    }
  }

  sortida << ")" << endl;
  sortida << "{" << endl;

  GenerateClassMethodBody(of, position);

  sortida << "}" << endl;
  sortida << endl;
}

////////////////////////////////////////////////////////////////////////////////

void ClassGenerator::GenerateClassMethodBody(std::ofstream* of, unsigned int position)
{
  ofstream& sortida = *of;
  sortida << "  // TODO" << endl;
}

////////////////////////////////////////////////////////////////////////////////
